/*
   This program implements a dummy string search algorithm. Initially we
   populate an array v with random characters in the range 'a-z'. The size of
   v is given by ARRAY_SIZE. Then, we give
   to each thread the task of:
   1) Generate NUM_QUERIES random pattern, with size
      [MINIMUM_STRING_SIZE, MAXIMUM_STRING_SIZE]
   2) Count the number of occurrences of the pattern in v.
   3) Report the maximum number of occurrences.
 */

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include "timetools.h"

inline char randChar() { return (char) (0xFF & rand()); }

//============================ BEGIN INPUT SIZE ==============================//
// Size of the smallest string that any thread will search for:
#define MINIMUM_STRING_SIZE   2

// Size of the largest string that any thread will search for:
#define MAXIMUM_STRING_SIZE  16 

// Number of searches that each thread will perform:
long NUM_QUERIES; 

// Size of the string where patterns will be searched:
long ARRAY_SIZE;
//============================== END INPUT SIZE ==============================//

// Array that will contain the search space.
char* v;

/*
   This function initializes an array with random characters. Each thread is
   in charge of initializing one block of the array.
 */
void initArray() {
   const long BLOCK_SIZE = ARRAY_SIZE;
   const long MY_START = 0;
   const long MY_END = BLOCK_SIZE;
   int i;

   for (i = MY_START; i < MY_END; i++) {
     // random
     v[i] = randChar();
   }
}

/*
   This function generates random patterns of characteres, and searches for
   them in the string.
 */
void searchStrings() {
   const long MY_REGION = ARRAY_SIZE;
   const long MY_START  = 0;
   const long MY_END    = MY_REGION;
   
   
   int i, j, k, num_occurrences, max_occur = 0;
   char most_freq[MAXIMUM_STRING_SIZE + 1];

   for (i = 0; i < MAXIMUM_STRING_SIZE + 1; i++) {
     most_freq[i] = '\0';
   }

   for (i = 0; i < NUM_QUERIES; i++) {
     int str_size = MAXIMUM_STRING_SIZE;
     if (str_size < MINIMUM_STRING_SIZE) {
       str_size = MINIMUM_STRING_SIZE;
     }
     char* pattern = (char*) malloc(str_size);
     for (j = 0; j < str_size; j++) {
       // random
       pattern[j] = randChar();
     }
     num_occurrences = 0;
     for (j = MY_START; j < MY_END - str_size + 1; j++) {
       int success = 1;
       for (k = 0; k < str_size; k++) {
         if (v[j + k] != pattern[k]) {
           success = 0;
           break;
         }
       }
       if (success) {
         num_occurrences++;
       }
     }
     if (num_occurrences > max_occur) {
       strncpy(most_freq, pattern, str_size);
       most_freq[str_size] = '\0';
       max_occur = num_occurrences;
     }
   }
}

/*
   Print the contents of the array.
 */
void printArray(char* array) {
  int t = 0;
  printf("Contents of the array:");
  for (t = 0; t < ARRAY_SIZE; t++) {
    if (t % 40 == 0) {
      printf("\n");
    }
    printf("%2c", array[t]);
  }
  printf("\n");
}

int main (int argc, char *argv[]) { 
  if (argc != 3) {
    fprintf(stderr, "Syntax: %s str_size num_queries\n", argv[0]);
    fprintf(stderr, "- num_points >> num_K\n");
    return -1;
  } else {

    srand(42);
    int t; 

    // Read input arguments
    ARRAY_SIZE  = atoi(argv[1]);
    NUM_QUERIES = atoi(argv[2]);

    // Initialize array data-structures
    v = (char*) malloc(ARRAY_SIZE);

    //========================= ARRAY INITIALIZATION ==========================//
    // Initialize the array of initArray threads:
    initArray();

    // printArray();

    //============================= ARRAY SEARCH ==============================//
    // Initialize the thread attributes again:

    // Initialize the array of searchString threads
#ifdef ENABLE_OUTPUT
    timespec startTime, endTime;
    readTime(&startTime);
#endif
        searchStrings();
#ifdef ENABLE_OUTPUT
    readTime(&endTime);

    const double elapsedTime = timeDiff(startTime, endTime);
    printf("SIZE %ld %ld\nTIME %f\n", ARRAY_SIZE, NUM_QUERIES, elapsedTime);
#endif
  }
	
	return 0;
}
